package com.xinyue.game.fish.service.rank;

import java.util.HashSet;
import java.util.Set;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import com.xinyue.game.fish.common.EnumRedisKey;
import com.xinyue.game.fish.common.SystemUtil;

public class GameRank implements IGameRank {

	private StringRedisTemplate redisTemplate;

	private Set<RankInfo> rankInfosCache;
	private long lastLoadTime = SystemUtil.currentTimeMillis();
	private long cacheExpireTime = 20 * 1000;
	private EnumRankType rankType;
	private String rankKey;

	public GameRank(StringRedisTemplate redisTemplate, EnumRankType rankType) {
		this.redisTemplate = redisTemplate;
		this.rankType = rankType;
	}

	public String getRankKey() {
		if (rankKey == null) {
			rankKey = EnumRedisKey.Rank.getRedisKey() + ":" + rankType.name().toLowerCase();
		}
		return rankKey;
	}

	private boolean isCacheExpire() {
		long nowTime = System.currentTimeMillis();
		long expire = nowTime - lastLoadTime;
		return expire > cacheExpireTime;
	}

	@Override
	public int updateRank(String member, long value) {
		String rankKey = this.getRankKey();
		redisTemplate.opsForZSet().add(rankKey, member, value);
		return getRank(member);
	}

	@Override
	public int getRank(String member) {
		String rankKey = this.getRankKey();
		Long rank = redisTemplate.opsForZSet().reverseRank(rankKey, member);
		return rank == null ? -1 : rank.intValue();
	}

	@Override
	public Set<RankInfo> getRankList(int count) {
		if (rankInfosCache != null) {
			if (!this.isCacheExpire()) {
				Set<RankInfo> rankInfos = this.rankInfosCache;
				return rankInfos;
			} else {
				this.rankInfosCache = null;
			}
		}
		synchronized (this) {
			if (rankInfosCache == null) {
				String rankKey = this.getRankKey();
				Set<ZSetOperations.TypedTuple<String>> results = redisTemplate.opsForZSet()
						.reverseRangeWithScores(rankKey, 0, count);
				int i = 1;
				Set<RankInfo> rankInfos = new HashSet<>(results.size());
				for (ZSetOperations.TypedTuple<String> tuple : results) {
					RankInfo rankInfo = new RankInfo();
					rankInfo.setMember(tuple.getValue());
					rankInfo.setRank(i++);
					rankInfo.setValue(tuple.getScore().longValue());
					rankInfos.add(rankInfo);
				}
		
				this.rankInfosCache = rankInfos;
				lastLoadTime = SystemUtil.currentTimeMillis();
			}
		}
		return rankInfosCache;
	}
}
